package g11.action;

import g11.actionutil.AppointmentUtil;
import g11.actionutil.AppointmentUtilImpl;
import g11.actionutil.EntityRltnUtil;
import g11.actionutil.EntityRltnUtilImpl;
import g11.actionutil.PatientUtilImpl;
import g11.dao.AppointmentDAO;
import g11.dao.AppointmentDAOImpl;
import g11.dao.DAOException;
import g11.dao.EmployeeDAO;
import g11.dao.EmployeeDAOImpl;
import g11.dao.PatientAssignmentDAOImpl;
import g11.dao.PatientDAO;
import g11.dao.PatientDAOImpl;
import g11.model.Appointment;
import g11.model.Employee;
import g11.model.Patient;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.log4j.Logger;
import org.apache.struts2.interceptor.SessionAware;

import com.opensymphony.xwork2.ActionSupport;

public class AppointmentAction extends ActionSupport implements SessionAware {

	/**
	 * the default serialVersionUID
	 */
	private static final long serialVersionUID = 1L;
	private Map<String, Object> session;
	/* Used for view appointment info & create/update appointment information */
	private Appointment retrievedAppointment;
	private Map<String, String> retrievedDoctors;
	private String selectedDoctorId;
	private String selectedAppointmentId;
	private String selectedPatientId;
	private String selectedDate;

	/* used for appointments list for doctor and staff */
	private List<Appointment> retrievedAppointments;
	private String currentEmployeeId;
	private final Logger log = Logger.getLogger(this.getClass());
	private Map<String, String> retrievedPatients;
	
	/*string to display the result of action*/
	private String resultString;

	/*
	 * actionMode: "showDoctorAppointment" "showStaffAppointment"
	 * "showAllAppointment"
	 * 
	 * "createAppointment" "updateAppointment"
	 */
	private String actionMode;

	public Map<String, Object> getSession() {
		return session;
	}

	public void setSession(Map session) {
		this.session = session;
	}
	
	public Map<String, String> getRetrievedDoctors() {
		return retrievedDoctors;
	}

	public void setRetrievedDoctors(Map<String, String> retrievedDoctors) {
		this.retrievedDoctors = retrievedDoctors;
	}

	public String getSelectedDoctorId() {
		return selectedDoctorId;
	}

	public void setSelectedDoctorId(String selectedDoctorId) {
		this.selectedDoctorId = selectedDoctorId;
	}

	public Appointment getRetrievedAppointment() {
		return retrievedAppointment;
	}

	public void setRetrievedAppointment(Appointment retrievedAppointment) {
		this.retrievedAppointment = retrievedAppointment;
	}

	public String getSelectedAppointmentId() {
		return selectedAppointmentId;
	}

	public void setSelectedAppointmentId(String selectedAppointmentId) {
		this.selectedAppointmentId = selectedAppointmentId;
	}

	public List<Appointment> getRetrievedAppointments() {
		return retrievedAppointments;
	}

	public void setRetrievedAppointments(List<Appointment> retrievedAppointments) {
		this.retrievedAppointments = retrievedAppointments;
	}

	public String getCurrentEmployeeId() {
		return currentEmployeeId;
	}

	public void setCurrentEmployeeId(String currentEmployeeId) {
		this.currentEmployeeId = currentEmployeeId;
	}

	public String getSelectedPatientId() {
		return selectedPatientId;
	}

	public void setSelectedPatientId(String selectedPatientId) {
		this.selectedPatientId = selectedPatientId;
	}

	public String getActionMode() {
		return actionMode;
	}

	public void setActionMode(String actionMode) {
		this.actionMode = actionMode;
	}

	public Map<String, String> getRetrievedPatients() {
		return retrievedPatients;
	}

	public void setRetrievedPatients(Map<String, String> retrievedPatients) {
		this.retrievedPatients = retrievedPatients;
	}

	public String getSelectedDate() {
		return selectedDate;
	}

	public void setSelectedDate(String selectedDate) {
		this.selectedDate = selectedDate;
	}

	public String getResultString() {
		return resultString;
	}

	public void setResultString(String resultString) {
		this.resultString = resultString;
	}

	public String initAppointmentViewPage() {
		session.put("triggeredAction", "initAppointmentViewPage");
		Integer appId = Integer.valueOf(this.selectedAppointmentId);
		AppointmentDAOImpl appDAO = new AppointmentDAOImpl();

		Appointment appointment = new Appointment();
		try {
			appointment = appDAO.getAppointmentById(appId);
		} catch (DAOException e) {
			e.printStackTrace();
			return ERROR;
		}
		if (appointment != null) {
			this.retrievedAppointment = appointment;
		} else {
			return ERROR;
		}
		session.put("actionResult","");
		return SUCCESS;
	}

	/*
	 * @param String currentEmployeeId String selectedAppointmentId
	 * 
	 * @return Map<String,String> retrievedDoctors Map<String,String>
	 * retrievedPatients Appointment retrievedAppointment
	 */
	public String initAppointmentUpdatePage() {
		session.put("triggeredAction", "initAppointmentUpdatePage");
		this.actionMode = "updateAppointment";
		Integer staffId = Integer.valueOf(this.currentEmployeeId);
		Integer appointmentId = Integer.valueOf(this.selectedAppointmentId);

		AppointmentDAOImpl appDao = new AppointmentDAOImpl();

		try {
			this.retrievedAppointment = appDao
					.getAppointmentById(appointmentId);
			
		} catch (DAOException e) {
			e.printStackTrace();
			return ERROR;
		}

		/*
		 * changed by Fern: getDoctorMapByStaffId and getPatientMapByStaffId has
		 * been moved to EntityRltnUtil
		 */
		// this.retrievedDoctors = this.getDoctorMapByStaffId(staffId);
		// this.retrievedPatients = this.getPatientMapByStaffId(staffId);
		EntityRltnUtil erUtil = new EntityRltnUtilImpl();
		try {
			this.retrievedDoctors = erUtil.getDoctorMapByStaffId(staffId);
			this.retrievedPatients = erUtil.getPatientMapByStaffId(staffId);
		} catch (DAOException e) {
			log.error("AppointmentAction:initAppointmentUpdatePage()", e);
			
			return ERROR;
		} finally {

		}

		this.selectedDate = this.retrievedAppointment.getAppointmentDate()
				.toString();
		session.put("actionResult","");
		return SUCCESS;
	}

	/*
	 * @param String currentEmployeeId
	 * 
	 * @return Map<String,String> retrievedDoctors Map<String,String>
	 * retrievedPatients Appointment retrievedAppointment
	 */
	public String initAppointmentCreatePage() {
		session.put("triggeredAction", "initAppointmentCreatePage");
		this.actionMode = "createAppointment";
		Integer patientId = Integer.valueOf(this.selectedPatientId);
		PatientDAOImpl pDao = new PatientDAOImpl();
		PatientUtilImpl pui = new PatientUtilImpl();
//		Integer staffId = Integer.valueOf(this.currentEmployeeId);
		this.retrievedAppointment = new Appointment();
		
		//get patient from selectedPatientId
		Patient patient = new Patient();
		try {
			patient = pDao.getPatientById(patientId);
		} catch (DAOException e) {
			e.printStackTrace();
			return ERROR;
		}
		
		//get defaultDoctor from patient
		Employee defaultDoctor = new Employee();
		defaultDoctor = pui.getDefaultDoctorByPatientId(patientId);
		retrievedAppointment.setDoctor(defaultDoctor);
		retrievedAppointment.setPatient(patient);
		
		session.put("actionResult","");
		return SUCCESS;
	}

	public String initAllAppointmentsPage() {
		session.put("triggeredAction", "initAllAppointmentsPage");
		Integer employeeId = Integer.valueOf(this.currentEmployeeId);
		EmployeeDAOImpl eDao = new EmployeeDAOImpl();
		AppointmentDAOImpl appDao = new AppointmentDAOImpl();
		AppointmentUtilImpl appImpl = new AppointmentUtilImpl();
		Employee employee = new Employee();
		try {
			employee = eDao.getEmployeeById(employeeId);
		} catch (DAOException e) {
			e.printStackTrace();
			return ERROR;
		}

		if (employee.getType() == 1) {// employee is a doctor
			this.actionMode = "showDoctorAppointment";
			try {
				this.retrievedAppointments = appDao
						.getPendingAppointmentByDoctor(employee);
			} catch (DAOException e) {
				e.printStackTrace();
				return ERROR;
			}

		} else if (employee.getType() == 2) {// employee is a staff
			this.actionMode = "showStaffAppointment";
			try {
				this.retrievedAppointments = appImpl
						.getAppointmentByStaff(employee);
			} catch (DAOException e) {
				e.printStackTrace();
				return ERROR;
			}

		}
		return SUCCESS;
	}

	/**
	 * @author Fern input: retrievedAppointment.appointmentDate
	 *         retrievedAppointment.startTime retrievedAppointment.endTime
	 *         retrievedAppointment.location selectedDoctorId selectedPatientId
	 *         output: Appointment appointment : the new createdAppointment, put
	 *         into this.retrievedAppointment
	 */
	public final String createAppointment() throws DAOException {
		session.put("triggeredAction", "createAppointment");
		/*
		 * need check if there's a conflict with doctor's appointments but we
		 * need get the doctor first
		 */

		EmployeeDAO edi = new EmployeeDAOImpl();
		Integer employeeId = Integer.valueOf(selectedDoctorId);
		Employee doctor = edi.getEmployeeById(employeeId);
		AppointmentUtil aui = new AppointmentUtilImpl();
		String appointmentDateString = this.selectedDate;
		DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
		java.util.Date appointmentDate = new java.util.Date();
		try {
			appointmentDate = formatter.parse(appointmentDateString);
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		java.sql.Date appointSQLDate = new java.sql.Date(
				appointmentDate.getTime());

		retrievedAppointment.setAppointmentDate(appointSQLDate);

		Integer patientID = Integer.valueOf(selectedPatientId);
		PatientDAO pdi = new PatientDAOImpl();
		Patient patient = pdi.getPatientById(patientID);
		retrievedAppointment.setPatient(patient);
		retrievedAppointment.setDoctor(doctor);
		retrievedAppointment.setStatus((byte) 0);
		
		if (!aui.checkAppointmentConflicByDoctor(doctor, retrievedAppointment,false)) {
			/*
			 * if there's no conflict, persist retrievedAppointment;need get the
			 * patient by patientId first
			 */
			log.info("AppointmentAction:createAppointment " + "no conflict");
			AppointmentDAO adi = new AppointmentDAOImpl();
			adi.createAppointment(retrievedAppointment);
			session.put("actionResult","Appointment successfully created !!");
		} else {
			/*
			 * there's a conflict, then ask staff to input appointment time
			 * again
			 */
			log.info("AppointmentAction:createAppointment " + "conflict");
			
			this.actionMode = "createAppointment";
//			this.resultString="There's a time conflict with another appointment, please reselect time!";
			session.put("actionResult","There's a time conflict with another appointment, please reselect time!");
			return ERROR;
		}

		return SUCCESS;
	}

	/**
	 * @ author Fern update a new appointment. The difference with
	 * createAppointment is Appointment.ID is known
	 * 
	 * @return Appointment this.retrievedAppointment
	 */
	public String updateAppointment() throws DAOException {
		session.put("triggeredAction", "updateAppointment");
		/*
		 * need check if there's a conflict with doctor's appointments but we
		 * need get the doctor first
		 */
		AppointmentUtil aui = new AppointmentUtilImpl();
		AppointmentDAO adi = new AppointmentDAOImpl();
		
		Appointment oldAppointment = new Appointment();
		oldAppointment = adi.getAppointmentById(retrievedAppointment.getAppointmentId());
		
		// compute appointmentDate
		String appointmentDateString = this.selectedDate;
		DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
		java.util.Date appointmentDate = new java.util.Date();
		try {
			appointmentDate = formatter.parse(appointmentDateString);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		java.sql.Date appointSQLDate = new java.sql.Date(
				appointmentDate.getTime());
		
		//update oldAppointment with new value
		oldAppointment.setAppointmentDate(appointSQLDate);
		oldAppointment.setStartTime(retrievedAppointment.getStartTime());
		oldAppointment.setEndTime(retrievedAppointment.getEndTime());
		oldAppointment.setLocation(retrievedAppointment.getLocation());

		if (!aui.checkAppointmentConflicByDoctor(oldAppointment.getDoctor(), oldAppointment,true)) {
			/*
			 * if there's no conflict, update retrievedAppointment and persist
			 * it;need get the patient by patientId first
			 */
//			log.info("AppointmentAction:updateAppointment " + "no conflict");
			adi.updateAppointment(oldAppointment);
			session.put("actionResult","Appointment successfully updated !!");
		} else {
			/*
			 * there's a conflict, then ask staff to input appointment time
			 * again
			 */
			
			log.info("AppointmentAction:updateAppointment " + "conflict");
			this.retrievedAppointment = oldAppointment;
			this.actionMode = "updateAppointment";
//			this.resultString="Error: There's a time conflict with another appointment, please reselect time!";
			session.put("actionResult","There's a time conflict with another appointment, please reselect time!");
			return ERROR;
		}
		this.retrievedAppointment = adi
				.getAppointmentById(retrievedAppointment.getAppointmentId());

		return SUCCESS;
	}

	/**
	 * @author Fern delete an existing appointment so we need check if this
	 *         appointment exist or not
	 * @input String retrievedAppointment.appointmentId
	 */
	public String deleteAppointment() throws DAOException {
		session.put("triggeredAction", "deleteAppointment");
		/*
		 * need to check if the appointment exists or not because of concurrency
		 */
		AppointmentDAO adi = new AppointmentDAOImpl();
		Integer appointmentId = Integer.valueOf(this.selectedAppointmentId);
		retrievedAppointment = adi.getAppointmentById(appointmentId);
		if (retrievedAppointment != null
				) {
			/*
			 * the appointment does exist
			 */
			log.info("AppointmentAction:deleteAppointment " + "to be deleted");
			adi.deleteAppointment(retrievedAppointment);
			session.put("actionResult","Appointment successfully cancelled !!");
		} else {
			log.info("AppointmentAction:deleteAppointment "
					+ "Failed to delete");
			session.put("actionResult","Delete appointment failed !!");
			return ERROR;
		}
		
		//retrieve Appointment list 
		Integer employeeId = Integer.valueOf(this.currentEmployeeId);
		EmployeeDAOImpl eDao = new EmployeeDAOImpl();
		AppointmentDAOImpl appDao = new AppointmentDAOImpl();
		AppointmentUtilImpl appImpl = new AppointmentUtilImpl();
		Employee employee = new Employee();
		try {
			employee = eDao.getEmployeeById(employeeId);
		} catch (DAOException e) {
			e.printStackTrace();
			return ERROR;
		}
		this.actionMode = "showStaffAppointment";
		try {
			this.retrievedAppointments = appImpl
					.getAppointmentByStaff(employee);
			session.put("actionResult","Cannot retrieve appointment list!!");
		} catch (DAOException e) {
			e.printStackTrace();
			return ERROR;
		}
		
		return SUCCESS;
	}

	public Map<String, String> getTimeMap() {
		Map<String, String> defScheduleMap = new TreeMap<String, String>();
		defScheduleMap.put("08:00", "08:00");
		defScheduleMap.put("08:30", "08:30");
		defScheduleMap.put("09:00", "09:00");
		defScheduleMap.put("09:30", "09:30");
		defScheduleMap.put("10:00", "10:00");
		defScheduleMap.put("10:30", "10:30");
		defScheduleMap.put("11:00", "11:00");
		defScheduleMap.put("11:30", "11:30");
		defScheduleMap.put("12:00", "12:00");
		defScheduleMap.put("12:30", "12:30");
		defScheduleMap.put("13:00", "13:00");
		defScheduleMap.put("13:30", "13:30");
		defScheduleMap.put("14:00", "14:00");
		defScheduleMap.put("14:30", "14:30");
		defScheduleMap.put("15:00", "15:00");
		defScheduleMap.put("15:30", "15:30");
		defScheduleMap.put("16:00", "16:00");
		defScheduleMap.put("16:30", "16:30");
		defScheduleMap.put("17:00", "17:00");
		return defScheduleMap;
	}

	public Map<String, String> getSearchTypeMap() {
		Map<String, String> searchTypeMap = new TreeMap<String, String>();
		searchTypeMap.put("0", "Date");
		searchTypeMap.put("1", "Time");
		searchTypeMap.put("2", "PatientId");
		return searchTypeMap;
	}

	/*
	 * The next two methods have been moved to EntityRltnImpl
	 * 
	 * private Map<String,String> getDoctorMapByStaffId(int staffId){
	 * EmployeeDAOImpl eDao = new EmployeeDAOImpl(); Employee staff = new
	 * Employee(); try { staff = eDao.getEmployeeById(staffId); } catch
	 * (DAOException e1) { e1.printStackTrace(); } WorkForDAO wDAO = new
	 * WorkForDAOImpl(); List<Employee> retrievedDoctorList = new
	 * ArrayList<Employee>(); try { retrievedDoctorList =
	 * wDAO.getDoctorList(staff); } catch (DAOException e) { // TODO
	 * Auto-generated catch block e.printStackTrace(); }
	 * 
	 * Map<String, String> doctorMap = new TreeMap<String, String>();
	 * for(Employee e:retrievedDoctorList){
	 * doctorMap.put(String.valueOf(e.getId()), e.getName()); } return
	 * doctorMap; }
	 */
	/*
	 * private Map<String, String> getPatientMapByStaffId(int staffId){
	 * EmployeeDAOImpl eDao = new EmployeeDAOImpl(); Employee staff = new
	 * Employee(); try { staff = eDao.getEmployeeById(staffId); } catch
	 * (DAOException e1) { e1.printStackTrace(); }
	 * 
	 * PatientUtilImpl paui = new PatientUtilImpl(); List<Patient>
	 * retrievedPatientList = new ArrayList<Patient>(); try {
	 * retrievedPatientList = paui.getPatientByStaffBelongTo(staff); } catch
	 * (DAOException e) { e.printStackTrace(); }
	 * 
	 * Map<String, String> patientMap = new TreeMap<String, String>();
	 * for(Patient e:retrievedPatientList){
	 * patientMap.put(String.valueOf(e.getId()), e.getName()); } return
	 * patientMap; }
	 */
	

}
